import React, { useEffect } from 'react';
import { Row, Col, Button, Form, Space, Table } from '@douyinfe/semi-ui';

import {
    SearchTablePageProps,
    SearchFormSchemaControl,
    SearchFormControlAction,
    SearchFormControlType,
    SearchFormSchemaButtonControl,
    SearchFormControlElement,
    SearchFormSchemaContainer,
    SearchFormElement,
    SearchFormSchemaRadioGroupControl,
    SearchFormSchemaSelectControl
} from './types';
import { Observer } from 'mobx-react';
import { IdValue, OptionProps, SearchResult } from '@ugeez/frontend-commons/lib/types';

const renderFormChild = (def: SearchFormElement, index: number, form: any): JSX.Element => {
    let child: JSX.Element;

    if (def['views']) {
        const con: SearchFormSchemaContainer = def as SearchFormSchemaContainer;
        const views: SearchFormControlElement[] = con.views || [];
        child = (
            <Space
                key={index}
                className={`search-form-inner-container`}
                vertical={false}
            >
                {views.map((subDef: SearchFormSchemaControl, i: number) => {
                    return renderFormChild(subDef, i, form);
                })}
            </Space>
        );
    } else {
        if (def.action === SearchFormControlAction.Search) {
            child = (
                <Form.Slot noLabel={true} key={index}>
                    <Button theme="solid" type="primary" htmlType="submit">
                        搜索
                    </Button>
                    <Button
                        theme="solid"
                        style={{ margin: '0 8px' }}
                        onClick={() => {
                            form.reset();
                        }}
                    >
                        重置
                    </Button>
                </Form.Slot>
            );
        } else {
            let control: React.ReactNode;
            const props: any = {...(def.props || {})};

            switch (def.view) {
                case SearchFormControlType.Input:
                    if (def.label) props.label = def.label;
                    else props.noLabel = true;
                    control = (
                        <Form.Input 
                            key={index}
                            field={def.name!}
                            label={def.label} 
                            placeholder={def.placeholder || ''} 
                            disabled={def.disabled} {...props} />
                    );
                    break;
                case SearchFormControlType.Button:
                    const btnDef: SearchFormSchemaButtonControl = def as SearchFormSchemaButtonControl;
                    control = (
                        <Form.Slot noLabel={true} key={index}>
                            <Button
                                theme="solid"
                                type={btnDef.type || 'primary'}
                                disabled={btnDef.disabled}
                                onClick={btnDef.onClick}
                                {...(def.props || {})}
                                {...props}
                            >
                                {btnDef.text}
                            </Button>
                        </Form.Slot>
                    );
                    break;
                case SearchFormControlType.RadioGroup:
                    const radioGroupDef: SearchFormSchemaRadioGroupControl = def as SearchFormSchemaRadioGroupControl;
                    if (def.label) props.label = def.label;
                    else props.noLabel = true;
                    control = (
                        <Form.RadioGroup
                            key={index}
                            field={def.name!}
                            label={def.label}
                            onChange={() => {
                                if (radioGroupDef.submitWhenChange) {
                                    form.submitForm();
                                }
                            }}
                            {...props}
                        >
                            {radioGroupDef.radioItems
                                ? radioGroupDef.radioItems.map((item: string | OptionProps, i: number) => {
                                      const value = typeof item === 'string' ? item : item.value;
                                      const label = typeof item === 'string' ? item : item.label;
                                      return (
                                          <Form.Radio key={i} value={value}>
                                              {label}
                                          </Form.Radio>
                                      );
                                  })
                                : null}
                        </Form.RadioGroup>
                    );
                    break;
                case SearchFormControlType.Select:
                    const selectDef: SearchFormSchemaSelectControl = def as SearchFormSchemaSelectControl;
                    if (def.label) props.label = def.label;
                    else props.noLabel = true;
                    control = (
                        <Form.Select
                            key={index}
                            field={def.name!}
                            label={def.label}
                            optionList={selectDef.options}
                            onChange={(newValue) => {
                                if (selectDef.onChange) {
                                    selectDef.onChange(newValue);
                                }
                                if (selectDef.submitWhenChange) {
                                    form.submitForm();
                                }
                            }}
                            {...props}
                        />
                    );
                    break;
                default:
                    //control = def.view as React.ReactNode;
                    break;
            }
            child = control;
        }
    }

    return child;
};

function SearchTablePage<T extends IdValue>({
    className,
    store,
    columns,
    formSchema,
    dataItemKey,
    selectable = false,
    onRowSelectionChange,
    onSearch,
    onError,
    children
}: SearchTablePageProps<T>): JSX.Element {

    const doSearch = (filter = store.filter, page = store.page, pageSize = store.pageSize) => {
        if (onRowSelectionChange) {
            onRowSelectionChange([], []);
        }

        store
            .search(filter, page, pageSize)
            .then((result: SearchResult<T>) => {
                if (onSearch) {
                    onSearch(result);
                }
            })
            .catch((err) => {
                if (onError) {
                    onError(err);
                }
            });
    };

    useEffect(() => {
        if (store && formSchema && formSchema.defaultFormData) {
            store.filter = { ...formSchema.defaultFormData };
        }
        // console.log('did mount!');
    }, []);

    useEffect(() => {
        // console.log('render');
    });

    return (
        <Observer>
            {() => {
                const { selectedKeys, data } = store;

                const rowSelection = {
                    selectedRowKeys: selectedKeys,
                    onChange: (selectedKeys, selectedItems) => {
                        store.select(selectedKeys, selectedItems);
                        if (onRowSelectionChange) {
                            onRowSelectionChange(selectedKeys, selectedItems);
                        }
                    }
                };
                return (
                    <div className={`search-table ${className}`}>
                        <Row>
                            <Col span={24}>
                                <Form
                                    className="ant-advanced-search-form"
                                    initValues={formSchema.defaultFormData}
                                    onSubmit={(values) => {
                                        doSearch(values);
                                    }}
                                    render={ ({ formApi }) => {
                                        return <>{
                                            formSchema.rows.map((row: SearchFormSchemaControl[], i: number) => {
                                                const size = 24;
                                                let restSize = size;
                                                let undefSizeNum = 0;
                                                row.forEach((def: SearchFormSchemaControl) => {
                                                    if (def.size) {
                                                        restSize -= def.size;
                                                    } else {
                                                        undefSizeNum++;
                                                    }
                                                });
                                                const avgSize = Math.round(restSize / undefSizeNum);
                                                let totalSize = 0;
                                                return (
                                                    <Row key={i} gutter={24}>
                                                        {row.map((def: SearchFormSchemaControl, j: number) => {
                                                            let defSize: number | undefined = def.size;
                                                            if (!defSize) {
                                                                defSize = avgSize;
                                                                if (totalSize + defSize > size) {
                                                                    defSize = size - totalSize;
                                                                }
                                                            }
                                                            totalSize += defSize;
    
                                                            return (
                                                                <Col key={j} span={defSize} style={{ textAlign: def['align'] ||  'left' }}>
                                                                    {renderFormChild(def, j, formApi)}
                                                                </Col>
                                                            );
                                                        })}
                                                    </Row>
                                                );
                                            })
                                        }</>;
                                    } }
                                >
                                </Form>
                            </Col>
                        </Row>
                        <Row>
                            <Col span={24}>
                                <Table
                                    rowSelection={selectable ? rowSelection : undefined}
                                    rowKey={dataItemKey || 'id'}
                                    columns={columns}
                                    dataSource={data}
                                    size="small"
                                    bordered
                                    pagination={{
                                        total: store.total,
                                        currentPage: store.page,
                                        pageSize: store.pageSize,
                                        showSizeChanger: false,
                                        onChange: (page) => {
                                            doSearch(store.filter, page);
                                        }
                                    }}
                                />
                            </Col>
                        </Row>
                        {children}
                    </div>
                );
            }}
        </Observer>
    );
}

export default SearchTablePage;
